package data

import (
	"context"
	"github.com/duke-git/lancet/convertor"
	"gorm.io/gorm"
	"time"

	"hellorockscache/internal/biz"

	"github.com/go-kratos/kratos/v2/log"
)

const (
	redisTestKey = "redis_test_key"
)

type greeterRepo struct {
	data *Data
	log  *log.Helper
}

// NewGreeterRepo .
func NewGreeterRepo(data *Data, logger log.Logger) biz.GreeterRepo {
	return &greeterRepo{
		data: data,
		log:  log.NewHelper(logger),
	}
}

func (r *greeterRepo) Save(ctx context.Context, g *biz.Greeter) (*biz.Greeter, error) {
	return g, nil
}

func (r *greeterRepo) Update(ctx context.Context, g *biz.Greeter) (*biz.Greeter, error) {
	return g, nil
}

func (r *greeterRepo) FindByID(context.Context, int64) (*biz.Greeter, error) {
	return nil, nil
}

func (r *greeterRepo) ListByHello(context.Context, string) ([]*biz.Greeter, error) {
	return nil, nil
}

func (r *greeterRepo) ListAll(context.Context) ([]*biz.Greeter, error) {
	return nil, nil
}

func (r *greeterRepo) TestRocks1(ctx context.Context, id int64) error {

	db := r.data.Mysql.Table(biz.TableName).WithContext(ctx)

	model := biz.Whw{}

	// 1、缓存过期的情况：从数据库中获取数据 Notice 高并发场景下会有"穿透"
	errFirst := db.Where("id = ?", id).First(&model).Error
	if errFirst != nil {
		return errFirst
	}

	// 2、更新到redis
	r.data.RedisCli.Set(ctx, redisTestKey, convertor.ToString(model.Count), time.Second*100)

	return nil
}

func (r *greeterRepo) TestRocks(ctx context.Context, id int64) error {
	db := r.data.Mysql.Table(biz.TableName).WithContext(ctx)

	_, errValue := r.data.RocksCache.Fetch2(ctx, redisTestKey, time.Second*100, func() (string, error) {
		model := biz.Whw{}
		// 模拟缓存过期的情况：从数据库中获取数据
		errFirst := db.Where("id = ?", id).First(&model).Error
		if errFirst != nil {
			return "", errFirst
		}

		// 把数据库中最新的值返回
		return convertor.ToString(model.Count), nil
	})
	if errValue != nil {
		return errValue
	}

	return nil
}

// Notice 考虑下需要更新数据的情况！
func (r *greeterRepo) TestRocks2(ctx context.Context, id, change int64) error {

	db := r.data.Mysql.Table(biz.TableName).WithContext(ctx)

	model := biz.Whw{}

	// 1、缓存过期的情况：从数据库中获取数据 Notice 高并发场景下会有"穿透"
	errFirst := db.Where("id = ?", id).First(&model).Error
	if errFirst != nil {
		return errFirst
	}

	// 2、更新到redis Notice 高并发情况下会出问题!!!会出现缓存与DB不一致的情况！
	// 因为：1、并发情况下所有协程从DB中获取的初始值是一样的，+操作后的结果跟实际预想的不一样 2、 += 操作不是原子的！
	r.data.RedisCli.Set(ctx, redisTestKey, convertor.ToString(model.Count+change), time.Second*100)

	// 3、更新数据库数据 Notice 这一步是并发安全的
	err := db.Where("id = ?", id).Update("count", gorm.Expr("count + ?", change)).Error
	if err != nil {
		return err
	}

	return nil
}
